import { ContextEvent, ContextType } from "../common/GameCost";
import { IContext, IKey, IModule } from "../common/Common";
import Utils from "../utils/Utils";


interface IRegistInfo {
    reg: new () => any;

    type: ContextType;
}

interface IregistInstance {
    instance: any;
    type: ContextType;
}

export default class Context {

    static Instance: Context = new Context();

    /**注册列表 */
    private readonly _registArray: Map<IKey, IRegistInfo>;

    /**实列列表*/
    private readonly _objs: Map<IKey, IregistInstance>;

    private constructor() {
        this._registArray = new Map<IKey, IRegistInfo>();
        this._objs = new Map<IKey, IregistInstance>();
    }

    register<T extends object>(c: new (...ages: any[]) => T, asType: ContextType) {
        let key = Utils.getGUIDByObject(c);
        let arr = this._registArray;
        !arr.has(key) && arr.set(key, { reg: c, type: asType });
        asType === ContextType.Manage && this.get(c);
        return key;
    }

    get<T extends object>(c: new (...ages: any[]) => T): T {
        let regs = this._registArray, key = Utils.getGUIDByObject(c);
        let info = regs.get(key);
        if (Utils.isNil(info)) {
            console.error(c, "tyr get unregistered object");
            return;
        }

        //生命周期在外面自己管理，比如UI这些
        if (info.type === ContextType.UI || info.type === ContextType.Dynamic) {
            return new info.reg();
        }

        let objs = this._objs;
        if (!objs.has(key)) {
            let obj = new c();
            objs.set(key, { instance: obj, type: info.type });

            //由于manage是注册实例化，所有initaalize放在注册后统一执行
            info.type !== ContextType.Manage && Utils.apply(obj, "initialize")
        }

        return objs.get(key).instance;
    }

    has(c: new () => any) {
        return this._registArray.has(Utils.getGUIDByObject(c));
    }


    recycleBynew(c: new () => any, reg: boolean = false) {
        let key = Utils.getGUIDByObject(c);
        this.recycle(key, reg);
    }

    recycleByObj(c: object, reg: boolean = false) {
        let pto = Reflect.getPrototypeOf(c);
        let key = Utils.getGUIDByObject(pto);
        this.recycle(key, reg);
    }


    /**
     * 释放
     * @param key 唯一id
     * @param unregist 是否移除注册信息
     */
    recycle(key: number, unregist: boolean) {
        let objs = this._objs, regs = this._registArray;
        if (objs.has(key)) {
            let v = objs.get(key)

            Utils.apply(v, "destroy");
            Utils.apply(v, "dispose");

            objs.delete(key);
        }

        if (unregist && regs.has(key)) {
            regs.delete(key);
        }
    }

    getInsArray(type: ContextType) {
        let arr: IModule[] = [];
        this._objs.forEach((v, k) => {
            if (v.type !== type) return;

            arr.push(v.instance);
        })

        return arr;
    }

    runEvent(type: ContextType, event: ContextEvent) {
        let arr = this.getInsArray(type);

        if (arr.length <= 0) return;

        for (let obj of arr) {

            Utils.apply(obj, event);
        }

    }

}
